package colibri.lcdui;

import colibri.App;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;

/**Constroi um formulário customizável.
 * @author Bayron Thiengo Quinelato
 */
public abstract class Form extends GameCanvas {
   
    private int x, y;
    private int height;
    // Background
    private Image imBackGround;
    private int backGroundColor;
    private int backGroundAnchor;
    // Background transparente
    private Image imTransparentBG;
    // Items controlers
    private int numOfItems;
    private int itemFocused;
    private boolean indicateTraverse;
    private boolean validateVisibility;
    private Item items[];
    // Commands
    private CommandHandler commandHandler;
    private CommandListener listener;
    // Touchscreen keyboard
    private TouchKeyboard keyborad;
    //ScrollBar
    private ScrollBar scrollBar;
    private boolean scrollable;
    private int scrollY;
    private int scrollH;
    public static final int SCROLL_TOP_DOWN = 0;
    public static final int SCROLL_BOTTON_UP = 1;
    private int scrollType = SCROLL_TOP_DOWN;
    // Tela anterior
    private Displayable beforeDisplayable;
    // Cabeçalho
    private Header header;
    // Rodapé
    private Footer footer;

    public Form(Displayable beforeDisplayable) {
        super(false);
        setFullScreenMode(true);
        this.beforeDisplayable = beforeDisplayable;

        x = 0;
        y = 0;
        App.width = getWidth();
        App.height = getHeight();
        App.halfWidth = App.width / 2;
        App.halfHeight = App.height / 2;

        numOfItems = 0;
        itemFocused = -1;

        scrollable = false;
        scrollY = -1;
        scrollH = -1;

        // Background
        backGroundColor = 0xFFFFFF;
        imBackGround = null;
        backGroundAnchor = 0;

        commandHandler = new CommandHandler(this);
    }

    public Displayable getBeforeDisplayable() {
        return beforeDisplayable;
    }

    protected abstract void callPaint(Graphics g);

    public void paint(Graphics g) {
        try {
            setFormHeight();

            // Se o teclado touchscreen estiver aberto, passa o conteúdo dele para o textfield que estã com foco
            if (keyborad != null && keyborad.isOpen) {
                if (items[itemFocused] != null && items[itemFocused] instanceof TextField && items[itemFocused].focus) {
                    ((TextField) items[itemFocused]).setText(keyborad.getText());
                }
            }
            // Salva as dimensões da tela
            if (scrollable && scrollBar != null)
                App.width = getWidth() - scrollBar.getWidth();
            else
                App.width = getWidth();
            App.height = getHeight();
            App.halfWidth = App.width / 2;
            App.halfHeight = App.height / 2;

            //Define a linha como sólida
            g.setStrokeStyle(0);

            //Limpa a tela
            g.setColor(0xFFFFFF);
            g.fillRect(0, 0, App.width, App.height);

            //Desenha o background
            if (imBackGround == null) {
                g.setColor(backGroundColor);
                g.fillRect(0, 0, App.width, App.height);
            } else {
                if (backGroundAnchor == (Graphics.TOP | Graphics.LEFT)) {
                    g.drawImage(imBackGround, 0, 0, Graphics.TOP | Graphics.LEFT);
                } else if (backGroundAnchor == (Graphics.TOP | Graphics.HCENTER)) {
                    g.drawImage(imBackGround, App.halfWidth, 0, (Graphics.TOP | Graphics.HCENTER));
                } else if (backGroundAnchor == (Graphics.TOP | Graphics.RIGHT)) {
                    g.drawImage(imBackGround, App.width, 0, (Graphics.TOP | Graphics.RIGHT));
                } else if (backGroundAnchor == (Graphics.VCENTER | Graphics.LEFT)) {
                    g.drawImage(imBackGround, 0, App.halfHeight, (Graphics.VCENTER | Graphics.LEFT));
                } else if (backGroundAnchor == (Graphics.VCENTER | Graphics.HCENTER)) {
                    g.drawImage(imBackGround, App.halfWidth, App.halfHeight, (Graphics.VCENTER | Graphics.HCENTER));
                } else if (backGroundAnchor == (Graphics.VCENTER | Graphics.RIGHT)) {
                    g.drawImage(imBackGround, App.width, App.halfHeight, (Graphics.VCENTER | Graphics.RIGHT));
                } else if (backGroundAnchor == (Graphics.BOTTOM | Graphics.LEFT)) {
                    g.drawImage(imBackGround, 0, App.height, (Graphics.BOTTOM | Graphics.LEFT));
                } else if (backGroundAnchor == (Graphics.BOTTOM | Graphics.HCENTER)) {
                    g.drawImage(imBackGround, App.halfWidth, App.height, (Graphics.BOTTOM | Graphics.HCENTER));
                } else if (backGroundAnchor == (Graphics.BOTTOM | Graphics.RIGHT)) {
                    g.drawImage(imBackGround, App.width, App.height, (Graphics.BOTTOM | Graphics.RIGHT));
                }
            }

            //Define a linha como sólida novamente
            g.setStrokeStyle(0);

            //Define o recrte da tela que será desenhado
            int clip[] = new int[4];
            clip[0] = g.getClipX();
            clip[1] = g.getClipY();
            clip[2] = g.getClipWidth();
            clip[3] = g.getClipHeight();

            for (int i = 0; i < numOfItems; i++) {
                paintItem(items[i], g, clip);
            }

            //Chama o método callPaint das classes herdeiras do Form
            g.setClip(0, getHeaderHeight(), getWidth(), App.height - getOccupiedHeight());
            callPaint(g);

            // Desenha o Header
            if (header != null) {
                paintItem(header, g, clip);
            }
            // Desenha o Footer
            if (footer != null) {
                paintItem(footer, g, clip);
            }
            // Desenha o ScrollBar
            if (scrollBar != null) {
                scrollBar.setCanvas(this);
                paintItem(scrollBar, g, clip);
            }

            // Desenha o fundo transparente
            if ((keyborad != null && keyborad.isOpen) || (commandHandler != null && commandHandler.isOpen())) {
                try {
                    if (imTransparentBG == null)
                        imTransparentBG = Image.createImage("/res/img/tansparent_background.png");
                    g.setClip(0, 0, App.width, App.height);
                    if (App.width > imTransparentBG.getWidth() || App.height > imTransparentBG.getHeight()) {
                        for (int l = 0; l < App.height; l += imTransparentBG.getHeight())
                            for (int c = 0; c < App.width; c += imTransparentBG.getWidth())
                                g.drawImage(imTransparentBG, c, l, Graphics.TOP | Graphics.LEFT);
                    } else
                        g.drawImage(imTransparentBG, 0, 0, Graphics.TOP | Graphics.LEFT);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            // Desenha os Commands
            if (commandHandler.numCommands > 0) {
                paintItem(commandHandler, g, clip);
            }
            // Desenha o teclado TouchScreen
            if (keyborad != null) {
                keyborad.setCanvas(this);
                paintItem(keyborad, g, clip);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalStateException("Colibri error: Falha ao desenhar o Form.");
        }
    }

    public int size() {
        return numOfItems;
    }

///######################### HEADER #########################
    public void setHeader(Image imHeader, int anchor) {
        if (imHeader == null) {
            throw new NullPointerException("Colibri error: Falha ao criar Header. O agumento 'imHeader' é nulo.");
        }
        header = new Header(imHeader, anchor);
    }

    public void setHeader(int headerColor, int headerHeight, int borderColor, int borderHeight) {
        header = new Header(headerColor, headerHeight, borderColor, borderHeight);
    }

    public void setHeaderText(String text, Font font, int x, int y, int anchor) {
        if (header != null) {
            header.setText(text, font, x, y, anchor);
        }
    }

    public void setHeaderText(String text, int x, int y, int anchor) {
        if (header != null) {
            header.setText(text, null, x, y, anchor);
        }
    }

    public void removeHeader() {
        header = null;
    }

    public int getHeaderHeight() {
        if (header != null) {
            return header.height;
        }
        return 0;
    }

    public void setHeaderTextColor(int color) {
        if (header != null) {
            header.setTextColor(color);
        }
    }

///######################### FOOTER #########################
    public void setFooter(Image imFoot, int anchor) {
        footer = new Footer(imBackGround, anchor);
        // Atualiza as dimensões dos comandos
        commandHandler.updateCommandSet();
    }

    public void setFooter(int footColor, int footHeight, int borderColor, int borderHeight) {
        footer = new Footer(footColor, footHeight, borderColor, borderHeight);
        // Atualiza as dimensões dos comandos
        commandHandler.updateCommandSet();
    }

    public void setFooterText(String text, Font font, int x, int y, int anchor) {
        if (footer != null) {
            footer.setText(text, font, x, y, anchor);
        }
    }

    public void removeFooter() {
        footer = null;
    }

    public int getFooterHeight() {
        if (footer != null) {
            return footer.height;
        }
        return 0;
    }

    public void setFooterTextColor(int color) {
        if (footer != null) {
            footer.setTextColor(color);
        }
    }

    public int getOccupiedHeight() {
        return getHeaderHeight() + getFooterHeight();
    }

///######################### ITENS #########################
    public int append(Item item) {
        return insert(numOfItems, item);
    }

    public int insert(int itemNum, Item item) {
        if(item.getCanvas() != null)
            throw new IllegalStateException();
        if (itemNum < 0 || itemNum > numOfItems)
            throw new IndexOutOfBoundsException("Colibri error: Falha ao adicionar novo Item ao Form. O argumento 'itemNum' é inválido.");
        if (item instanceof Header
                || item instanceof Footer
                || item instanceof CommandHandler
                || item instanceof ScrollBar
                || item instanceof TouchKeyboard)
            throw new IllegalArgumentException("Colibri error: Falha ao adicionar novo Item ao Form. O argumento 'item' é inválido.");
        if (item == null)
            return -1;
        if (items == null) {
            items = new Item[numOfItems];
        }
        if (items.length == numOfItems) {
            Item newItems[] = new Item[numOfItems + 4];
            System.arraycopy(items, 0, newItems, 0, itemNum);
            System.arraycopy(items, itemNum, newItems, itemNum + 1, numOfItems - itemNum);
            items = newItems;
        } else if(itemNum != numOfItems) {
            System.arraycopy(items, itemNum, items, itemNum + 1, numOfItems - itemNum);
        }
        numOfItems++;
        items[itemNum] = null;
        set(itemNum, item);
        return itemNum;
    }

    public void set(int itemNum, Item item) {
        if(item.getCanvas() != null)
            throw new IllegalStateException();
        if(itemNum < 0 || itemNum >= numOfItems)
            throw new IndexOutOfBoundsException("Colibri error: Falha ao inserir item ao Form. O argumento 'itemNum' é inválido.");
        Item oldItem = items[itemNum];
        if(oldItem != null)
            oldItem.setCanvas(null);
        item.setCanvas(this);
        // Ajusta o posicionamento vertical do item caso a rolagem esteja ativa
        if (scrollable && scrollBar != null) {
            int offset = scrollBar.getCount() * scrollBar.getOffset();
            item.setScrollableY(items[itemFocused].getInitialY() - offset);
        }
        items[itemNum] = item;
        if (itemFocused < 0) {
            downItemFocused();
        }
        System.gc();
    }

    public Item get(int itemNum) {
        if(itemNum < 0 || itemNum >= numOfItems)
            throw new IndexOutOfBoundsException("Colibri error: Falha ao pegar item do Form. O argumento 'itemNum' é inválido.");
        return items[itemNum];
    }

    public void delete(int itemNum) {
        if (itemNum < 0 || itemNum >= numOfItems)
            throw new IndexOutOfBoundsException("Colibri error: Falha ao remover Item do Form. O argumento 'itemNum' é inválido.");
        Item deletedItem = items[itemNum];
        deletedItem.setCanvas(null);
        if (itemFocused >= itemNum) {
            upItemFocused();
        }
        numOfItems--;
        if (itemNum < numOfItems) {
            System.arraycopy(items, itemNum + 1, items, itemNum, numOfItems - itemNum);
        }
        items[numOfItems] = null;
        if(numOfItems == 0) {
            itemFocused = -1;
            if (items.length > 4)
                items = new Item[4];
        }
    }

    public void deleteAll() {
        for (int i = 0; i < numOfItems; i++) {
            items[i].setCanvas(null);
            items[i] = null;
        }
        if(items.length > 4)
            items = new Item[4];
        numOfItems = 0;
        itemFocused = -1;
    }

    private void paintTraversalIndicator(Graphics g, int x, int y) {
        g.setColor(0x606060);
        g.drawRect(x - 3, y - 3, items[itemFocused].width + 5, items[itemFocused].height + 5);
        g.setColor(0);//Verificar este ponto.
    }

    private void paintItem(Item item, Graphics g, int clip[]) {
        if (item == null || !item.visible) {
            return;
        }
        int iX = item.x;
        int iY = item.y;
        int iW = item.width;
        int iH = item.height;
        switch (item.anchor) {
            case Graphics.TOP | Graphics.LEFT:
                iX -= x;
                iY -= y;
                break;
            case Graphics.TOP | Graphics.HCENTER:
                iX -= item.width / 2 - x;
                iY -= y;
                break;
            case Graphics.TOP | Graphics.RIGHT:
                iX -= item.width - x;
                iY -= y;
                break;
            case Graphics.VCENTER | Graphics.LEFT:
                iX -= x;
                iY -= item.height / 2 - y;
                break;
            case Graphics.VCENTER | Graphics.HCENTER:
                iX -= item.width / 2 - x;
                iY -= item.height / 2 - y;
                break;
            case Graphics.VCENTER | Graphics.RIGHT:
                iX -= item.width - x;
                iY -= item.height / 2 - y;
                break;
            case Graphics.BOTTOM | Graphics.LEFT:
                iX -= x;
                iY -= item.height - y;
                break;
            case Graphics.BOTTOM | Graphics.HCENTER:
                iX -= item.width / 2 - x;
                iY -= item.height - y;
                break;
            case Graphics.BOTTOM | Graphics.RIGHT:
                iX -= item.width - x;
                iY -= item.height - y;
                break;
            case Graphics.BASELINE | Graphics.LEFT:
                iX -= x;
                iY -= item.height - y;
                break;
            case Graphics.BASELINE | Graphics.HCENTER:
                iX -= item.width / 2 - x;
                iY -= item.height - y;
                break;
            case Graphics.BASELINE | Graphics.RIGHT:
                iX -= item.width - x;
                iY -= item.height - y;
                break;
            default:
                iX -= x;
                iY -= y;
                break;
        }
        if ((iY + item.height < clip[1] || iY > clip[1] + clip[3]) && !validateVisibility) {
            return;
        }
        if (!(item instanceof Header)
                && !(item instanceof Footer)
                && !(item instanceof CommandHandler)
                && !(item instanceof ScrollBar)
                && !(item instanceof TouchKeyboard)) {
            if (iX < 0)
                iX = 0;
            if (iY < getHeaderHeight())
                iY = getHeaderHeight();
            if (iW > App.width)
                iW = App.width;
            if (iH > App.height - getOccupiedHeight())
                iH = App.height - getOccupiedHeight();
        }
        g.setClip(iX, iY, iW, iH);
        if (g.getClipWidth() > 0 && g.getClipHeight() > 0) {
            item.callPaint(g);
        }
        if (itemFocused >= 0 && numOfItems >= 1 && item == items[itemFocused] && indicateTraverse) {
            g.clipRect(iX - 4, iY - 4, item.width + 8, item.height + 8);
            paintTraversalIndicator(g, iX, iY);
            g.setClip(clip[0], clip[1], clip[2], clip[3]);
        }
    }

///######################### BACKGROUND #########################
    public final void setBackGround(int color) {
        if (color < 0) {
            throw new IllegalArgumentException("Colibri error: Falha ao definir uma cor para o plano de fundo do Form. O argumento 'color' é inválido.");
        }
        backGroundColor = color;
    }

    public final void setBackGround(Image image, int anchor) {
        if (image == null)
            throw new NullPointerException("Colibri error: Falha ao definir uma imagem para o plano de fundo do Form. O argumento 'image' é nulo.");
        imBackGround = image;
        backGroundAnchor = anchor;
    }

///######################### TOUCH KEYBOARD #########################
    public void setTouchKeyBoard(boolean flag) {
        if (flag && App.ISTOUCHSCREEN) {
            keyborad = new TouchKeyboard();
            if (items != null && itemFocused >= 0 && itemFocused < items.length && items[itemFocused] instanceof TextField) {
                keyborad.setTextField((TextField) items[itemFocused]);
            }
        } else {
            keyborad = null;
        }
    }

    public final void setItemFocused(int itemNum) {
        if (itemNum < 0 || itemNum >= numOfItems)
            throw new IndexOutOfBoundsException("Colibri error: Falha ao definir o Item focado do Form. O argumento 'itemNum' é inválido.");
        itemFocused = itemNum;
        for (int i = 0; i < numOfItems; i++)
            items[i].focus = false;
        items[itemFocused].focus = true;

        if (keyborad != null && items[itemFocused] != null && items[itemFocused] instanceof TextField)
            keyborad.setTextField((TextField) items[itemFocused]);
    }

    public void setItemFocused(Item item) {
        for (int i = 0; i < numOfItems; i++) {
            if (items[i] == item && item.focusable) {
                for (int j = 0; j < numOfItems; j++)
                    items[j].focus = false;
                itemFocused = i;
                items[itemFocused].focus = true;
                if (keyborad != null && items[itemFocused] != null && items[itemFocused] instanceof TextField)
                    keyborad.setTextField((TextField) items[itemFocused]);
                return;
            }
        }
    }
    
    public void setScrollable(boolean scrollable) {
        this.scrollable = scrollable;
    }

    public void setScrollType(int type) {
        if (type == SCROLL_TOP_DOWN || type == SCROLL_BOTTON_UP)
            scrollType = type;
    }

    public void setScrollableBounds(int y, int height) {
        if (y < 0 || height <= 0)
            return;
        scrollY = y;
        scrollH = height;
    }

    public void setScrollImages(Image imBackground, Image imArrowUp, Image imArrowDown, Image imBar, Image imBarBorderUp, Image imBarBorderDown) {
        ScrollBar.setImages(imBackground, imArrowUp, imArrowDown, imBar, imBarBorderUp, imBarBorderDown);
    }

    public void setScrollColors(int colorBackground, int colorBar, int colorBarBorder) {
        ScrollBar.setColors(colorBackground, colorBar, colorBarBorder);
    }

    private void setFormHeight() {
        height = 0;
        if (items == null) {
            scrollBar = null;
            return;
        }
        // Verifica a posição e tamanho do item mais inferior da tela para definir o tamanho total do Form
        for (int i = 0; i < items.length; i++)
            if (items[i] != null && items[i].getInitialY() + items[i].getHeight() > height)
                height = items[i].getInitialY() + items[i].getHeight();
        if (!scrollable) {
            scrollBar = null;
            return;
        }
        // Verifica se o tamanho total do Form ultrapaça o tamanho da tela, se sim, cria e exibe a scrollbar, senão, mantém a scroll bar nula
        if (height > App.height - getFooterHeight()) {
            if (scrollBar == null) {
                if (scrollY < getHeaderHeight())
                    scrollY = getHeaderHeight();
                if (scrollH > App.height - getOccupiedHeight() || scrollH < 0)
                    scrollH = App.height - getOccupiedHeight();
                scrollBar = new ScrollBar(this, scrollY, scrollH);
                if (scrollType == SCROLL_BOTTON_UP)
                    scrollBar.setCount(scrollBar.getMaxCount());
                if (scrollType == SCROLL_BOTTON_UP) {
                    setItemFocused(numOfItems - 1);
                    int offset = scrollBar.getCount() * scrollBar.getOffset();
                    for (int i = 0; i < numOfItems; i++)
                        if (items[i] != null)
                            items[i].setScrollableY(items[i].getInitialY() - offset);
                }
            }

            // Verifica se o item selecionado ultrapaça o limite da tela, se sim, ele ativa a rolagem da scrollbar, senão, a desativa
            if (items[itemFocused] != null && items[itemFocused].getInitialY() + items[itemFocused].getHeight() > App.height - getFooterHeight())
                scrollBar.setActive(true);
            else
                scrollBar.setActive(false);
            return;
        } else
            scrollBar = null;
    }

    public int getFormHeight() {
        return height;
    }

    private void upItemFocused() {
        // Se a tela tiver rolagem e o item selecionado for uma imagem e essa imagem for maior que a tela, então faz a rolagem sem pular todo o item
        if (scrollable && itemFocused > -1 && items[itemFocused] != null && scrollBar != null) {
            int offset = scrollBar.getCount() * scrollBar.getOffset();
            if (items[itemFocused] instanceof ImageItem) {
                if (items[itemFocused].getInitialY() - offset < scrollY) {
                    scrollBar.up();
                    offset = scrollBar.getCount() * scrollBar.getOffset();
                    items[itemFocused].setScrollableY(items[itemFocused].getInitialY() - offset);
                    return;
                }
            }
        }
        boolean change = true;
        for (int i = 0; i < numOfItems; i++) {
            if (items[i] instanceof ChoiceGroup && ((ChoiceGroup) items[i]).isFixed) {
                change = false;
            }
        }
        if (itemFocused > 0 && change) {
            for (int i = 0; i < numOfItems; i++) {
                items[i].focus = false;
            }
            for (int i = itemFocused - 1; i >= 0; i--) {
                if (items[i].focusable) {
                    itemFocused = i;
                    items[itemFocused].focus = true;
                    if (keyborad != null && items[itemFocused] != null && items[itemFocused] instanceof TextField) {
                        keyborad.setTextField((TextField) items[itemFocused]);
                    }
                    break;
                }
            }
            if (itemFocused < numOfItems && items[itemFocused].focusable && !items[itemFocused].focus) {
                items[itemFocused].focus = true;
                if (keyborad != null && items[itemFocused] != null && items[itemFocused] instanceof TextField) {
                    keyborad.setTextField((TextField) items[itemFocused]);
                }
            }
        }
        // Verifica se o item selecionado ultrapaça o limite da tela, se sim, ele ajusta a rolagem da scrollbar e o posicionamento do item
        if (scrollable && itemFocused > -1 && items[itemFocused] != null && scrollBar != null) {
            int offset = scrollBar.getCount() * scrollBar.getOffset();
            if (items[itemFocused].getInitialY() - offset < scrollY) {
                for (int i = scrollBar.getMaxCount(); i >= 0; i--) {
                    scrollBar.setCount(i);
                    offset = scrollBar.getCount() * scrollBar.getOffset();
                    if (items[itemFocused].getInitialY() - offset > scrollY) {
                        for (int j = 0; j < numOfItems; j++) {
                            if (items[j] != null) {
                                items[j].setScrollableY(items[j].getInitialY() - offset);
                            }
                        }
                        break;
                    }
                }
            }
        }
    }

    private void downItemFocused() {
        // Se a tela tiver rolagem e o item selecionado for uma imagem e essa imagem for maior que a tela, então faz a rolagem sem pular todo o item
        if (scrollable && itemFocused > -1 && items[itemFocused] != null && scrollBar != null) {
            int offset = scrollBar.getCount() * scrollBar.getOffset();
            if (items[itemFocused] instanceof ImageItem) {
                if (items[itemFocused].getInitialY() - offset + items[itemFocused].getHeight() > scrollY + scrollH) {
                    scrollBar.down();
                    offset = scrollBar.getCount() * scrollBar.getOffset();
                    items[itemFocused].setScrollableY(items[itemFocused].getInitialY() - offset);
                    return;
                }
            }
        }
        boolean change = true;
        for (int i = 0; i < numOfItems; i++) {
            if (items[i] instanceof ChoiceGroup && ((ChoiceGroup) items[i]).isFixed) {
                change = false;
            }
        }
        if (itemFocused < numOfItems - 1 && change) {
            for (int i = 0; i < numOfItems; i++) {
                items[i].focus = false;
            }
            for (int i = itemFocused + 1; i < numOfItems; i++) {
                if (items[i].focusable) {
                    itemFocused = i;
                    items[itemFocused].focus = true;
                    if (keyborad != null && items[itemFocused] != null && items[itemFocused] instanceof TextField) {
                        keyborad.setTextField((TextField) items[itemFocused]);
                    }
                    break;
                }
            }
            if (itemFocused > -1 && items[itemFocused].focusable && !items[itemFocused].focus) {
                items[itemFocused].focus = true;
                if (keyborad != null && items[itemFocused] != null && items[itemFocused] instanceof TextField) {
                    keyborad.setTextField((TextField) items[itemFocused]);
                }
            }
        }
        // Verifica se o item selecionado ultrapaça o limite da tela, se sim, ele ajusta a rolagem da scrollbar e o posicionamento do item
        if (scrollable && itemFocused > -1 && items[itemFocused] != null && scrollBar != null) {
            int offset = scrollBar.getCount() * scrollBar.getOffset();
            if (items[itemFocused].getInitialY() - offset + items[itemFocused].getHeight() > scrollY + scrollH) {
                for (int i = scrollBar.getCount(); i <= scrollBar.getMaxCount(); i++) {
                    scrollBar.setCount(i);
                    offset = scrollBar.getCount() * scrollBar.getOffset();
                    if (items[itemFocused].getInitialY() - offset + items[itemFocused].getHeight() < scrollY + scrollH) {
                        for (int j = 0; j < numOfItems; j++)
                            if (items[j] != null)
                                items[j].setScrollableY(items[j].getInitialY() - offset);
                        break;
                    }
                }
            }
        }
    }

///################################# KEY EVENTS ################################
    protected void keyPressed(int keyCode) {
        // Ações do teclado touch screen
        if (keyborad != null) {
            boolean open = keyborad.isOpen;
            keyborad.callKeyPressed(keyCode);
            if (open) {
                repaint();
                return;
            }
        }
        // Ações dos commands
        if (commandHandler.numCommands > 0 && commandHandler.visible) {
            if (commandHandler.isOpen()) {
                commandHandler.callKeyPressed(keyCode);
                repaint();
                return;
            }
            commandHandler.callKeyPressed(keyCode);
        }
        // Ações do aplicativo do usuário
        callKeyPressed(keyCode);
        // Ações dos itens.
        if (commandHandler.numCommands <= 0 || !commandHandler.isOpen() || !commandHandler.visible) {
            if (scrollBar != null) {
                scrollBar.callKeyPressed(keyCode);
            }
            for (int i = 0; i < numOfItems; i++) {
                if (items[i].focus) {
                    items[i].callKeyPressed(keyCode);
                }
            }
        }
        // Redesenha toda a tela
        repaint();
    }

    protected void keyReleased(int keyCode) {
        // Ações do teclado touch screen
        if (keyborad != null) {
            boolean open = keyborad.isOpen;
            keyborad.callKeyReleased(keyCode);
            if (open) {
                repaint();
                return;
            } else if (items[itemFocused] != null
                    && items[itemFocused] instanceof TextField
                    && items[itemFocused].focus) {
                keyborad.setText(((TextField) items[itemFocused]).getText());
            }
        }
        // Ações dos botões
        if (commandHandler.numCommands > 0 && commandHandler.visible) {
            if (commandHandler.isOpen()) {
                commandHandler.callKeyReleased(keyCode);
                repaint();
                return;
            }
            commandHandler.callKeyReleased(keyCode);
        }
        if (keyborad != null && keyborad.isOpen) {
            return;
        }
        // Controle do foco dos itens
        int gameAction = getGameAction(keyCode);
        if (App.platform == App.PLATFORM_BLACKBERRY) {
            gameAction = keyCode;
        }
        switch (gameAction) {
            case App.UP:
                upItemFocused();
                break;
            case App.DOWN:
                downItemFocused();
                break;
        }
        // Ações do aplicativo do usuário
        callKeyReleased(keyCode);
        //Ações dos itens
        if (commandHandler.numCommands <= 0 || !commandHandler.isOpen() || !commandHandler.visible) {
            if (scrollBar != null) {
                scrollBar.callKeyReleased(keyCode);
            }
            for (int i = 0; i < numOfItems; i++) {
                if (items[i].focus) {
                    items[i].callKeyReleased(keyCode);
                }
            }
        }
        // Redesenha toda a tela
        repaint();
    }

    protected void keyRepeated(int keyCode) {
        // Ações do teclado touch screen
        if (keyborad != null) {
            boolean open = keyborad.isOpen;
            keyborad.callKeyRepeated(keyCode);
            if (open) {
                repaint();
                return;
            } else if (items[itemFocused] != null
                    && items[itemFocused] instanceof TextField
                    && items[itemFocused].focus) {
                keyborad.setText(((TextField) items[itemFocused]).getText());
            }
        }
        // Ações dos Commands
        if (commandHandler.numCommands > 0 && commandHandler.visible) {
            if (commandHandler.isOpen()) {
                commandHandler.callKeyRepeated(keyCode);
                repaint();
                return;
            }
            commandHandler.callKeyRepeated(keyCode);
        }
        if (keyborad != null && keyborad.isOpen) {
            return;
        }
        // Controle do foco dos itens
        int gameAction = getGameAction(keyCode);
        if (App.platform == App.PLATFORM_BLACKBERRY) {
            gameAction = keyCode;
        }
        switch (gameAction) {
            case App.UP:
                upItemFocused();
                break;
            case App.DOWN:
                downItemFocused();
                break;
        }
        // Ações do aplicativo do usuário
        callKeyRepeated(keyCode);
        //Ações dos itens
        if (commandHandler.numCommands <= 0 || !commandHandler.isOpen() || !commandHandler.visible) {
            if (scrollBar != null) {
                scrollBar.callKeyRepeated(keyCode);
            }
            for (int i = 0; i < numOfItems; i++) {
                if (items[i].focus) {
                    items[i].callKeyRepeated(keyCode);
                }
            }
        }
        // Redesenha toda a tela
        repaint();
    }

    protected void callKeyPressed(int keyCode) {
    }

    protected void callKeyReleased(int keyCode) {
    }

    protected void callKeyRepeated(int keyCode) {
    }

///################################ TOUCH EVENTS ###############################
    protected void pointerPressed(int x, int y) {
        // Ações do teclado touch screen
        if (keyborad != null) {
            boolean open = keyborad.isOpen;
            keyborad.callPointerPressed(x, y);
            if (open) {
                repaint();
                return;
            }
        }
        // Ações dos botões
        if (commandHandler.numCommands > 0 && commandHandler.visible) {
            if (commandHandler.isOpen()) {
                commandHandler.callPointerPressed(x, y);
                repaint();
                return;
            }
            commandHandler.callPointerPressed(x, y);
        }
        // Ações do aplicativo do usuário
        callPointerPressed(x, y);
        // Ações dos itens.
        if (commandHandler.numCommands <= 0 || !commandHandler.isOpen() || !commandHandler.visible) {
            if (scrollBar != null) {
                scrollBar.callPointerPressed(x, y);
            }
            for (int i = 0; i < numOfItems; i++) {
                if (items[i].focus) {
                    items[i].callPointerPressed(x, y);
                }
            }
        }
        // Redesenha toda a tela
        repaint();
    }

    protected void pointerReleased(int x, int y) {
        // Ações do teclado touch screen
        if (keyborad != null) {
            boolean open = keyborad.isOpen;
            keyborad.callPointerReleased(x, y);
            if (open) {
                repaint();
                return;
            } else if (items[itemFocused] != null
                    && items[itemFocused] instanceof TextField
                    && items[itemFocused].focus) {
                keyborad.setText(((TextField) items[itemFocused]).getText());
            }
        }
        // Ações dos botões
        if (commandHandler.numCommands > 0 && commandHandler.visible) {
            if (commandHandler.isOpen()) {
                commandHandler.callPointerReleased(x, y);
                repaint();
                return;
            }
            commandHandler.callPointerReleased(x, y);
        }
        // Controle do foco dos itens
        if (commandHandler.numCommands <= 0 || !commandHandler.isOpen() || !commandHandler.visible) {
            for (int i = 0; i < numOfItems; i++) {
                if (x > items[i].x && x < items[i].x + items[i].width
                        && y > items[i].y && y < items[i].y + items[i].height) {
                    if (items[i].focusable) {
                        setItemFocused(i);
                    }
                    break;
                }
            }
        }
        // Ações do aplicativo do usuário
        callPointerReleased(x, y);
        // Ações dos itens
        if (commandHandler.numCommands <= 0 || !commandHandler.isOpen() || !commandHandler.visible) {
            if (scrollBar != null) {
                scrollBar.callPointerReleased(x, y);
            }
            for (int i = 0; i < numOfItems; i++) {
                if (items[i].focus) {
                    items[i].callPointerReleased(x, y);
                }
            }
        }
        // Redesenha toda a tela
        repaint();
    }

    protected void pointerDragged(int x, int y) {
        // Ações do teclado touch screen
        if (keyborad != null) {
            boolean open = keyborad.isOpen;
            keyborad.callPointerDragged(x, y);
            if (open) {
                repaint();
                return;
            } else if (items[itemFocused] != null
                    && items[itemFocused] instanceof TextField
                    && items[itemFocused].focus) {
                keyborad.setText(((TextField) items[itemFocused]).getText());
            }
        }
        // Ações dos botões
        if (commandHandler.numCommands > 0 && commandHandler.visible) {
            commandHandler.callPointerDragged(x, y);
            if (commandHandler.isOpen()) {
                repaint();
                return;
            }
        }
        // Ações do aplicativo do usuário
        callPointerDragged(x, y);
        // Ações dos itens
        if (commandHandler.numCommands <= 0 || !commandHandler.isOpen() || !commandHandler.visible) {
            if (scrollBar != null) {
                scrollBar.callPointerDragged(x, y);
            }
            if (keyborad != null) {
                keyborad.callPointerDragged(x, y);
            }
            for (int i = 0; i < numOfItems; i++) {
                if (items[i].focus) {
                    items[i].callPointerDragged(x, y);
                }
            }
        }
        // Redesenha toda a tela
        repaint();
    }

    protected void callPointerPressed(int x, int y) {
    }

    protected void callPointerReleased(int x, int y) {
    }

    protected void callPointerDragged(int x, int y) {
    }

//------------------------------ Commands ----------------------------------------
    public void addCommand(Command cmd) {
        if (cmd == null) {
            throw new NullPointerException();
        }
        addCommandImpl(cmd);
    }

    public void removeCommand(Command cmd) {
        removeCommandImpl(cmd);
    }

    public void setCommandListener(CommandListener listener) {
        if (App.platform == App.PLATFORM_BLACKBERRY) {
            super.setCommandListener(listener);
        }
        this.listener = listener;
    }

    protected CommandListener getCommandListener() {
        return listener;
    }

    private void addCommandImpl(Command cmd) {
        if (App.platform == App.PLATFORM_BLACKBERRY) {
            super.addCommand(cmd);
            return;
        }
        commandHandler.addCommand(cmd);
    }

    private void removeCommandImpl(Command cmd) {
        if (App.platform == App.PLATFORM_BLACKBERRY) {
            super.removeCommand(cmd);
            return;
        }
        commandHandler.removeCommand(cmd);
    }

    public void setCommandTextColor(int coloroOut, int colorIn) {
        commandHandler.setTextColor(coloroOut, colorIn);
    }

    public void setCommandMenuTextColor(int coloroOut, int colorIn) {
        commandHandler.setMenuTextColor(coloroOut, colorIn);
    }

    public void setCommandBackgroundColor(int colorOut, int colorIn) {
        commandHandler.setBackgroundColor(colorOut, colorIn);
    }

    public void addSubCommand(Command cmd, Command subCmd) {
        if (App.platform == App.PLATFORM_BLACKBERRY) {
            super.removeCommand(cmd);
            super.addCommand(subCmd);
            return;
        }
        commandHandler.addSubCommand(cmd, subCmd);
    }

    public void removeSubCommands(Command cmd) {
        if (App.platform == App.PLATFORM_BLACKBERRY) {
            return;
        }
        commandHandler.removeSubCommands(cmd);
    }
}
